from ctypes import cast
from ctypes.wintypes import MSG, LPRECT

import win32con
import win32gui
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QCloseEvent, QCursor
from PyQt5.QtWidgets import QWidget
from PyQt5.QtWinExtras import QtWin
from qframelesswindow.utils.win32_utils import Taskbar
from qframelesswindow.windows import LPNCCALCSIZE_PARAMS

from app.common.os_utils import getWindowsVersion
from app.common.utils import win_utils


class FramelessWindow(QWidget):
    """无框窗户"""

    BORDER_WIDTH = 5

    def __init__(self, parent=None):
        super(FramelessWindow, self).__init__(parent)
        self._isResizeEnabled = True  # 是否允许调整大小

        # 删除窗口边框
        if getWindowsVersion() > 7:
            self.setWindowFlags(self.windowFlags() | Qt.FramelessWindowHint)
        else:
            self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowMinMaxButtonsHint)

        # 添加DWM阴影和窗口动画
        self.windowEffect.addWindowAnimation(self.winId())

        # 处理不同dpi的多屏幕
        self.windowEffect.screenChanged.connect(self.onScreenChanged)

        self.resize(500, 500)

    def setResizeEnabled(self, isEnabled: bool):
        """ set whether resizing is enabled """
        self._isResizeEnabled = isEnabled

    def nativeEvent(self, eventType, message):
        """
        处理Windows消息
        :param eventType:
        :param message:
        :return:
        """
        msg = MSG.from_address(message.__int__())
        if msg.message == win32con.WM_NCHITTEST and self._isResizeEnabled:
            pos = QCursor.pos()
            xPos = pos.x() - self.x()
            yPos = pos.y() - self.y()
            w, h = self.width(), self.height()
            lx = xPos < self.BORDER_WIDTH
            rx = xPos > w - self.BORDER_WIDTH
            ty = yPos < self.BORDER_WIDTH
            by = yPos > h - self.BORDER_WIDTH
            if lx and ty:
                return True, win32con.HTTOPLEFT
            elif rx and by:
                return True, win32con.HTBOTTOMRIGHT
            elif rx and ty:
                return True, win32con.HTTOPRIGHT
            elif lx and by:
                return True, win32con.HTBOTTOMLEFT
            elif ty:
                return True, win32con.HTTOP
            elif by:
                return True, win32con.HTBOTTOM
            elif lx:
                return True, win32con.HTLEFT
            elif rx:
                return True, win32con.HTRIGHT
        elif msg.message == win32con.WM_NCCALCSIZE:
            if msg.wParam:
                rect = cast(msg.lParam, LPNCCALCSIZE_PARAMS).contents.rgrc[0]
            else:
                rect = cast(msg.lParam, LPRECT).contents

            isMax = win_utils.is_maximized(msg.hWnd)
            isFull = win_utils.is_maximized(msg.hWnd)

            # 调整客户端rect的大小
            if isMax and not isFull:
                thickness = win_utils.get_resize_border_thickness(msg.hWnd)
                rect.top += thickness
                rect.left += thickness
                rect.right -= thickness
                rect.bottom -= thickness

            # 处理启用自动隐藏任务栏的情况
            if (isMax or isFull) and Taskbar.isAutoHide():
                position = Taskbar.getPosition(msg.hWnd)
                if position == Taskbar.LEFT:
                    rect.top += Taskbar.AUTO_HIDE_THICKNESS
                elif position == Taskbar.BOTTOM:
                    rect.bottom -= Taskbar.AUTO_HIDE_THICKNESS
                elif position == Taskbar.LEFT:
                    rect.left += Taskbar.AUTO_HIDE_THICKNESS
                elif position == Taskbar.RIGHT:
                    rect.right -= Taskbar.AUTO_HIDE_THICKNESS

            result = 0 if not msg.wParam else win32con.WVR_REDRAW
            return True, result

        return QWidget.nativeEvent(self, eventType, message)

    def onScreenChanged(self):
        """

        :return:
        """
        h_wnd = int(self.windowHandle().winId())
        win32gui.SetWindowPos(h_wnd, win32con.HWND_TOPMOST, 0, 0, 0, 0, win32con.SWP_NOMOVE | win32con.SWP_NOSIZE)


class AcrylicWindow(FramelessWindow):
    """亚克力窗口"""

    def __init__(self, parent=None):
        super(AcrylicWindow, self).__init__(parent)
        self.close_by_key = False  # 是否按键关闭

        QtWin.enableBlurBehindWindow(self.winId(), True)

        # 去除边框并添加阴影
        version = getWindowsVersion()
        if version == 7:
            self.setWindowFlags(Qt.WindowMinMaxButtonsHint | Qt.FramelessWindowHint)
            self.windowEffect.addShadowEffect(self.winId())
            self.windowEffect.setAeroEffect(self.winId())
        else:
            self.setWindowFlags(self.windowFlags() | Qt.FramelessWindowHint)
            self.windowEffect.setAcrylicEffect(self.winId())
            if version == 11:
                self.windowEffect.addShadowEffect(self.winId())

        self.windowEffect.addWindowAnimation(self.winId())
        self.setStyleSheet("background:transparent")

    def nativeEvent(self, event_type, message):
        """
        处理Windows消息
        :param event_type: 
        :param message: 
        :return: 
        """
        msg = MSG.from_address(message.__int__())
        if msg.message == win32con.WM_SYSKEYDOWN:
            if msg.wParam == win32con.VK_F4:
                self.close_by_key = True
                QApplication.sendEvent(self, QCloseEvent())
                return False, 0

        return super().nativeEvent(event_type, message)

    def closeEvent(self, e):
        quit_on_close = QApplication.quitOnLastWindowClosed()
        if not self.__closeByKey or quit_on_close:
            self.close_by_key = False
            return super().closeEvent(e)

        self.close_by_key = False
        self.hide()


if __name__ == '__main__':
    import sys
    from PyQt5.QtWidgets import QApplication

    app = QApplication(sys.argv)
    w = AcrylicWindow()
    w.show()
    app.exec_()
